package com.castle.fortress.admin.oa.rest;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.castle.fortress.admin.core.constants.GlobalConstants;
import com.castle.fortress.admin.oa.dto.AttendanceSettingDto;
import com.castle.fortress.admin.oa.entity.AttendanceRecordEntity;
import com.castle.fortress.admin.oa.dto.AttendanceRecordDto;
import com.castle.fortress.admin.oa.entity.AttendanceSettingDateEntity;
import com.castle.fortress.admin.oa.enums.AttendanceRecordStatusEnum;
import com.castle.fortress.admin.oa.enums.AttendanceRecordTypeEnum;
import com.castle.fortress.admin.oa.enums.AttendanceTypeEnum;
import com.castle.fortress.admin.oa.service.AttendanceSettingService;
import com.castle.fortress.admin.system.entity.SysUser;
import com.castle.fortress.admin.oa.service.AttendanceRecordService;
import com.castle.fortress.admin.utils.LocationUtil;
import com.castle.fortress.common.exception.ErrorException;
import com.castle.fortress.common.respcode.BizErrorCode;
import com.castle.fortress.common.utils.ConvertUtil;
import com.castle.fortress.admin.utils.WebUtil;
import com.castle.fortress.common.entity.RespBody;
import com.castle.fortress.common.exception.BizException;
import com.castle.fortress.common.respcode.GlobalRespCode;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.logging.log4j.util.Strings;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.*;

/**
 * 上下班考勤记录 api 控制器
 *
 * @author whc
 * @since 2022-11-04
 */
@Api(tags="上下班考勤记录api管理控制器")
@RestController
@RequestMapping("/api/oa/attendanceRecord")
public class ApiAttendanceRecordController {
	@Autowired
	private AttendanceRecordService attendanceRecordService;

	@Autowired
	private AttendanceSettingService attendanceSettingService;


	/**
	 * 上下班考勤记录的分页展示
	 * @param attendanceRecordDto 上下班考勤记录实体类
	 * @param currentPage 当前页
	 * @param size  每页记录数
	 * @return
	 */
	@ApiOperation("上下班考勤记录分页展示")
	@GetMapping("/page")
	public RespBody<IPage<AttendanceRecordDto>> pageAttendanceRecord(AttendanceRecordDto attendanceRecordDto, @RequestParam(required = false) Integer currentPage, @RequestParam(required = false)Integer size){
		Integer pageIndex= currentPage==null? GlobalConstants.DEFAULT_PAGE_INDEX:currentPage;
		Integer pageSize= size==null? GlobalConstants.DEFAULT_PAGE_SIZE:size;
		Page<AttendanceRecordDto> page = new Page(pageIndex, pageSize);

		IPage<AttendanceRecordDto> pages = attendanceRecordService.pageAttendanceRecord(page, attendanceRecordDto);
		return RespBody.data(pages);
	}

	//验证都放在这里
	private void verification(AttendanceRecordDto attendanceRecordDto) {

		if (WebUtil.currentUser()==null){
			throw new ErrorException(GlobalRespCode.NO_LOGIN_ERROR);
		}
		if (attendanceRecordDto == null) {
			throw new BizException(GlobalRespCode.PARAM_MISSED);
		}
		if (attendanceRecordDto.getSettId() == null) {
			throw new BizException(BizErrorCode.NO_CONFIG);
		}
		AttendanceSettingDto setting = attendanceSettingService.getByIdExtends(attendanceRecordDto.getSettId());
		if (setting == null) {
			throw new BizException(BizErrorCode.NO_CONFIG);
		}
		//验证设置是否存在 前端也要做
		if (setting.getAttendanceSettingDateEntity() == null || setting.getAttendanceSettingDateEntity().getWorkDay() == null) {
			throw new BizException(BizErrorCode.NO_CONFIG_DATE);
		}
		//查询设置是否为同一个
		SysUser currentUser = WebUtil.currentUser();
		AttendanceSettingDto currentUserSetting = attendanceSettingService.currentUserSetting(currentUser, AttendanceTypeEnum.COMMUTE.getCode());
		if (currentUserSetting == null) {
			throw new BizException(BizErrorCode.NO_CONFIG);
		}
		if (!currentUserSetting.getId().equals(attendanceRecordDto.getSettId())) {
			throw new BizException(BizErrorCode.NO_CONFIG);
		}
		//验证是否在工作日内
		String workDay = setting.getAttendanceSettingDateEntity().getWorkDay();
		final boolean contains = Arrays.asList(workDay.split(";")).contains(String.valueOf(new Date().getDay()));
		if (!contains) {
			//不在工作日抛出错误
			throw new BizException(BizErrorCode.NO_WORKDAY);
		}
//        获取本次的打卡经纬度 与设置经纬度做比对 结果如果超出设置*1000 那就说明不在范围内
		if (attendanceRecordDto.getRange() == null || "".equals(attendanceRecordDto.getRange())) {
			throw new BizException(BizErrorCode.NO_RANGE);
		}
		if (attendanceRecordDto.getAddress() == null || "".equals(attendanceRecordDto.getAddress())) {
			throw new BizException(BizErrorCode.NO_ADDRESS);
		}
		String[] range = attendanceRecordDto.getRange().split(",");
		String[] setRange = setting.getAddressRange().split(",");

		double distance = LocationUtil.getDistance(Double.parseDouble(range[1]), Double.parseDouble(range[0]), Double.parseDouble(setRange[1]), Double.parseDouble(setRange[0]));
		if (distance * 1000 > Double.parseDouble(setting.getDistance())) {
			//不满足打卡距离
			throw new BizException(BizErrorCode.NOT_ENOUGH_DISTANCE);
		}
	}


	/**
	 * 上下班考勤记录保存
	 *
	 * @param attendanceRecordDto 上下班考勤记录实体类
	 * @return
	 */
	@ApiOperation("上下班考勤记录保存")
	@PostMapping("/save")
	public RespBody<Object> saveAttendanceRecord(@RequestBody AttendanceRecordDto attendanceRecordDto, @RequestParam(required = false) String timeTest) {
		this.verification(attendanceRecordDto);
		SysUser currentUser = WebUtil.currentUser();
		AttendanceSettingDto setting = attendanceSettingService.getByIdExtends(attendanceRecordDto.getSettId());
		AttendanceSettingDateEntity settingDate = setting.getAttendanceSettingDateEntity();
		Integer type = -1;
		Integer status = -1;
		String gmtTime = "";
		String attendanceTime = "";
		//组装考勤时间范围
		Date timeBase = DateUtil.beginOfDay(new Date());
		String[] startTime = settingDate.getStartTime().split(":");
		String[] endTime = settingDate.getEndTime().split(":");
		DateTime start = DateUtil.offsetMinute(DateUtil.offsetHour(timeBase, Integer.parseInt(startTime[0])), Integer.parseInt(startTime[1]));
		DateTime end = DateUtil.offsetMinute(DateUtil.offsetHour(timeBase, Integer.parseInt(endTime[0])), Integer.parseInt(endTime[1]));
		//组装上班时间范围
		Date amBase = DateUtil.beginOfDay(new Date());
		String[] amStartTime = settingDate.getAmStartTime().split(":");
		String[] amEndTime = settingDate.getAmEndTime().split(":");
		DateTime amStart = DateUtil.offsetMinute(DateUtil.offsetHour(amBase, Integer.parseInt(amStartTime[0])), Integer.parseInt(amStartTime[1]));
		DateTime amEnd = DateUtil.offsetMinute(DateUtil.offsetHour(amBase, Integer.parseInt(amEndTime[0])), Integer.parseInt(amEndTime[1]));
		//组装下班时间范围
		String[] pmStartTime = settingDate.getPmStartTime().split(":");
		String[] pmEndTime = settingDate.getPmEndTime().split(":");
		Date pmBase = DateUtil.beginOfDay(new Date());
		DateTime pmStart = DateUtil.offsetMinute(DateUtil.offsetHour(pmBase, Integer.parseInt(pmStartTime[0])), Integer.parseInt(pmStartTime[1]));
		DateTime pmEnd = DateUtil.offsetMinute(DateUtil.offsetHour(pmBase, Integer.parseInt(pmEndTime[0])), Integer.parseInt(pmEndTime[1]));

		Date now = new Date();
		long nowTime = now.getTime();
		boolean amCondition = nowTime >= amStart.getTime() && nowTime <= amEnd.getTime();
		boolean pmCondition = nowTime >= pmStart.getTime() && nowTime <= pmEnd.getTime();
		if (!amCondition && !pmCondition) {
			throw new BizException(BizErrorCode.TIME_NOT_YET);
		}
		if (amCondition) {
			HashMap<String, Object> amQuery = new HashMap<>();
			AttendanceRecordEntity existsAm = attendanceRecordService.getByDate(amQuery);
			if (existsAm != null && existsAm.getId() != null) {
				//不可以重复打卡 直接返回
				throw new BizException(BizErrorCode.NOT_REPEATABLE);
			}
			//说明在打卡时间段内 并且今日未打卡 那就正常打卡
			//填充字段
			type = AttendanceRecordTypeEnum.AM.getCode();
			status = AttendanceRecordStatusEnum.NORMAL.getCode();
			//判断是否迟到
			int lateTime = Integer.parseInt(settingDate.getLateTime());
			lateTime = 1000 * 60 * lateTime;
			//如果当前时间 大于 考勤开始时间+允许迟到分钟数  =迟到
			if (nowTime > (start.getTime() + lateTime)) {
				status = AttendanceRecordStatusEnum.BE_LATE.getCode();
			}
			//组装gmt
			gmtTime = settingDate.getAmStartTime() + "~" + settingDate.getAmEndTime();
			attendanceTime = setting.getAttendanceSettingDateEntity().getStartTime();
		}

		if (pmCondition) {
			HashMap<String, Object> pmQuery = new HashMap<>();
			pmQuery.put("type", AttendanceRecordTypeEnum.PM.getCode());
			AttendanceRecordEntity existsPm = attendanceRecordService.getByDate(pmQuery);
			//填充字段
			type = AttendanceRecordTypeEnum.PM.getCode();
			status = AttendanceRecordStatusEnum.NORMAL.getCode();
			gmtTime = settingDate.getPmStartTime() + "~" + settingDate.getPmEndTime();
			attendanceTime = setting.getAttendanceSettingDateEntity().getEndTime();
			//当前时间+允许早退时间 < 考勤结束时间=早退
			int leaveTime = Integer.parseInt(settingDate.getLeaveTime());
			leaveTime = leaveTime * 60 * 1000;
			if ((nowTime + leaveTime) < end.getTime()) {
				status = AttendanceRecordStatusEnum.LEAVE_EARLY.getCode();
			}
			if (existsPm != null && existsPm.getId() != null) {
				//更新打卡时间
				existsPm.setClockIn(now);
				existsPm.setStatus(status);
				attendanceRecordService.updateById(existsPm);
				return RespBody.success("更新打卡时间成功");
			}
			//说明在打卡时间段内 并且今日未打卡  字段已经填充不需要做额外操作
		}
		if (status < 0) {
			throw new BizException(BizErrorCode.UNKNOWN_EXCEPTION);
		}
		if ("~".equals(gmtTime)) {
			throw new BizException(BizErrorCode.UNKNOWN_EXCEPTION);
		}
		if (type < 0) {
			throw new BizException(BizErrorCode.UNKNOWN_EXCEPTION);
		}
		//填充字段
		attendanceRecordDto.setStatus(status);
		attendanceRecordDto.setGmtTime(gmtTime);
		attendanceRecordDto.setAttendanceTime(attendanceTime);
		attendanceRecordDto.setUserId(currentUser.getId());
		attendanceRecordDto.setType(type);
		attendanceRecordDto.setDate(DateUtil.today());
		attendanceRecordDto.setClockIn(now);
		attendanceRecordDto.setDeptId(currentUser.getDeptId());
		AttendanceRecordEntity attendanceRecordEntity = ConvertUtil.transformObj(attendanceRecordDto, AttendanceRecordEntity.class);
		if (attendanceRecordService.save(attendanceRecordEntity)) {
			return RespBody.data("打卡成功");
		} else {
			return RespBody.fail(GlobalRespCode.OPERATE_ERROR);
		}
	}


	/**
	 * 上下班考勤记录编辑
	 * @param attendanceRecordDto 上下班考勤记录实体类
	 * @return
	 */
	@ApiOperation("上下班考勤记录编辑")
	@PostMapping("/edit")
	public RespBody<String> updateAttendanceRecord(@RequestBody AttendanceRecordDto attendanceRecordDto){
		if(attendanceRecordDto == null || attendanceRecordDto.getId() == null || attendanceRecordDto.getId().equals(0L)){
			throw new BizException(GlobalRespCode.PARAM_MISSED);
		}
			AttendanceRecordEntity attendanceRecordEntity = ConvertUtil.transformObj(attendanceRecordDto,AttendanceRecordEntity.class);
		if(attendanceRecordService.updateById(attendanceRecordEntity)){
			return RespBody.data("保存成功");
		}else{
			return RespBody.fail(GlobalRespCode.OPERATE_ERROR);
		}
	}

	/**
	 * 上下班考勤记录删除
	 * @param ids 上下班考勤记录id集合
	 * @return
	 */
	@ApiOperation("上下班考勤记录删除")
	@PostMapping("/delete")
	public RespBody<String> deleteAttendanceRecord(@RequestBody List<Long> ids){
		if(ids == null || ids.isEmpty()){
			throw new BizException(GlobalRespCode.PARAM_MISSED);
		}
		if(attendanceRecordService.removeByIds(ids)) {
			return RespBody.data("保存成功");
		}else{
			return RespBody.fail(GlobalRespCode.OPERATE_ERROR);
		}
	}

	/**
	 * 上下班考勤记录详情
	 * @param id 上下班考勤记录id
	 * @return
	 */
	@ApiOperation("上下班考勤记录详情")
	@GetMapping("/info")
	public RespBody<AttendanceRecordDto> infoAttendanceRecord(@RequestParam Long id){
		if(id == null){
			throw new BizException(GlobalRespCode.PARAM_MISSED);
		}
		AttendanceRecordDto attendanceRecordDto =  attendanceRecordService.getByIdExtends(id);
		return RespBody.data(attendanceRecordDto);
	}


}
